package com.wang.jmonkey.interceptor.config;

import com.wang.jmonkey.common.support.yml.TransformYmlFactory;
import com.wang.jmonkey.interceptor.ControllerInterceptor;
import com.wang.jmonkey.interceptor.LogInterceptor;
import com.wang.jmonkey.interceptor.LoginUserInterceptor;
import com.wang.jmonkey.interceptor.PageInterceptor;
import com.wang.jmonkey.interceptor.handler.result.ExceptionResultHandlerManager;
import com.wang.jmonkey.interceptor.property.InterceptorProperty;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.type.filter.AspectJTypeFilter;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.PostConstruct;

/**
 * @Description 自动装配
 * @Author HeJiawang
 * @Date 2021/5/20 11:53
 */
@PropertySource(value= {InterceptorProperty.INTERCEPTOR_PROPERTY_PATH} , factory = TransformYmlFactory.class)
@EnableConfigurationProperties(InterceptorProperty.class)
@Configuration
public class InterceptorAutoConfig {

    private RedisTemplate<String , Object> redis;

    private GenericApplicationContext context;

    private RabbitTemplate rabbit;

    public InterceptorAutoConfig(RabbitTemplate rabbit, RedisTemplate<String, Object> redis, GenericApplicationContext context) {
        this.rabbit = rabbit;
        this.redis = redis;
        this.context = context;
    }

    @PostConstruct
    private void initHandler() {
        final ClassPathScanningCandidateComponentProvider classPathScanningCandidateComponentProvider
                = new ClassPathScanningCandidateComponentProvider(false);

        classPathScanningCandidateComponentProvider.addIncludeFilter(
                new AspectJTypeFilter("com.wang.jmonkey.interceptor.handler..*" , this.getClass().getClassLoader())
        );

        classPathScanningCandidateComponentProvider.findCandidateComponents("com.wang.jmonkey.interceptor.handler").forEach(bd -> {
            if (ExceptionResultHandlerManager.class.getName().equals(bd.getBeanClassName())) {
                bd.setScope("prototype");
            }

            context.registerBeanDefinition(bd.getBeanClassName(), bd);
        });
    }

    /**
     * Controller层拦截器
     * @param interceptorProperty 拦截器配置
     * @return advisor
     */
    @Bean
    @ConditionalOnProperty(name = "jmonkey.interceptor.controller", matchIfMissing = true)
    public DefaultPointcutAdvisor controllerAdvisor(InterceptorProperty interceptorProperty) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(
                String.join(" || ", interceptorProperty.getControllerInterceptor().getExpressionList())
        );

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(new ControllerInterceptor(context, redis));
        advisor.setOrder(interceptorProperty.getControllerInterceptor().getOrder());
        return advisor;
    }

    /**
     * 日志拦截器
     * @param interceptorProperty 拦截器配置
     * @return advisor
     */
    @Bean
    @ConditionalOnProperty(name = "jmonkey.interceptor.log", matchIfMissing = true)
    public DefaultPointcutAdvisor logAdvisor(InterceptorProperty interceptorProperty) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(interceptorProperty.getLogInterceptor().getExpression());

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(new LogInterceptor(rabbit, context));
        advisor.setOrder(interceptorProperty.getLogInterceptor().getOrder());
        return advisor;
    }

    /**
     * 装配登陆用户信息的拦截器
     * @param interceptorProperty 拦截器配置
     * @return advisor
     */
    @Bean
    @ConditionalOnProperty(name = "jmonkey.interceptor.login-user", matchIfMissing = true)
    public DefaultPointcutAdvisor loginUserAdvisor(InterceptorProperty interceptorProperty) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(
                String.join(" || ", interceptorProperty.getLoginUserInterceptor().getExpressionList())
        );

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(new LoginUserInterceptor(redis, context));
        advisor.setOrder(interceptorProperty.getLoginUserInterceptor().getOrder());
        return advisor;
    }

    /**
     * 分页工具拦截器配置
     * @param interceptorProperty interceptorProperty
     * @return advisor
     */
    @Bean
    @ConditionalOnProperty(name = "jmonkey.interceptor.page", matchIfMissing = true)
    public DefaultPointcutAdvisor pageAdvisor(InterceptorProperty interceptorProperty) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(interceptorProperty.getPageInterceptor().getExpression());

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(new PageInterceptor(context));
        advisor.setOrder(interceptorProperty.getPageInterceptor().getOrder());
        return advisor;
    }

}
